\documentclass[a4paper,openany,12pt]{report}
\usepackage{listings}
\usepackage{graphicx}

\newcommand{\horrule}[1]{\rule{\linewidth}{#1}} 	% Horizontal rule

\title{
		\vspace*{-1in} 	
		\normalfont \normalsize \textsc{
		Universidad Nacional de C\'{o}rdoba\\
		C\'{a}tedra de Sist. Operativos I\\
        Trabajo Pr\'{a}ctico N$^{\circ}$ 1} \\ [18px]
		\horrule{2pt} \\[0.5cm]
		\huge Observando el comportamiento de Linux \\
		\horrule{2pt} \\[0.5cm]
}
\author{
		\normalfont 								\normalsize
        Rodriguez Isle\~{n}o Gonzalo Exequiel\\[-3pt]		\normalsize
        Roth\"{a}rmel Diego Joaqu\'{i}n\\[-3pt]		\normalsize
        Agosto 22, 2014
}
\date{}
\begin{document}
\maketitle

\newpage
\tableofcontents

\newpage
\chapter{Introducci\'{o}n}\label{cap.introduccion}
\pagenumbering{arabic} % para empezar la numeración con números

\section{Kernel de Linux}
Se puede pensar al kernel de Linux como una colecci\'{o}n de funciones y estructuras
de datos, estas estructuras contienen la visi\'{o}n del kernel respecto al estado
del sistema, donde cada estado del mismo, se ve reflejado en el cambio de estas
variables. En Linux por ser de c\'{o}digo abierto, es posible inspeccionar como
est\'{a}n manejadas estas variables.

\section{Tareas m\'{a}s importantes}
\begin{itemize}
  \item Administraci\'{o}n de la memoria para todos los programas y procesos en ejecuci\'{o}n.
  \item Administraci\'{o}n del tiempo de procesador que los programas y procesos en ejecuci\'{o}n utilizan.
  \item Es el encargado de que podamos acceder a los perif\'{e}ricos/elementos de nuestro ordenador de una manera c\'{o}moda.
\end{itemize}

\section{El directorio /proc}
El directorio /proc es algo raro. Realmente no existe, sin embargo se puede explorar. Sus archivos de tama\~{n}o 0 no son ni binarios ni textos, sin embargo se puede examinarlos y desplegar su contenido. Este directorio especial contiene todos los detalles del sistema Linux, incluyendo el kernel, procesos y par\'{a}metros de configuraci\'{o}n.
Bajo Linux, todo es administrado como un archivo, el directorio /proc contiene una extra\~{n}o tipo de archivo: archivos virtuales. Estos archivos son listados, pero realmente no existen en disco; el sistema operativo los crea al vuelo si se trata de leerlos.
La mayor\'{i}a de los archivos virtuales siempre tienen una marca de tiempo (timestamp) actual, lo que indica que est\'{a}n constantemente siendo actualizados. El directorio /proc en si mismo es creado cada vez que se arranca el equipo. Se requiere ser root para poder examinar completamente el directorio en su totalidad; algunos de los archivos (tales como los relacionados a procesos) son propiedad del usuario que los ejecut\'{o}. Y aunque casi tdos los archivos son de solo lectura, hay algunos pocos con permisos de escritura (notablemente en /proc/sys) que permiten realizar cambios en los parámetros del kernel.

\chapter{Desarrollo}\label{cap.desarrollo}
\section{Parte A}
En primer lugar se procedi\'{o} a realizar un recorrido general
de los archivos en la carpeta /proc, asimismo se ejecut\'{o} el comando \verb=man proc=
el cual tiene la documentaci\'{o}n completa de cada archivo, una
peque\~{n}a descripci\'{o}n del mismo, el formato en el cual se organiza y la tarea que
desempe\~{n}a, esto para poder entender como se organizan los directorios y archivos entonces as\'{i} poder detectar
las variables buscadas. En segundo lugar se abri\'{o} cada archivo en el cual se realizo una inspecci\'{o}n minuciosa a su contenido con la finalidad de constatar la ubicaci\'{o}n de las variables necesarias para la realizaci\'{o}n del trabajo pr\'{a}ctico.

\section{Parte B}
\subsection{Descripci\'{o}n del c\'{o}digo}
El c\'{o}digo est\'{a} compuesto por peque\~{n}as funciones que acceden de manera
independiente a los archivos correspondientes para extraer la informaci\'{o}n,
parsearla y posteriormente entregarsela al usuario de una manera entendible a trav\'{e}s de la pantalla.
Las rutas hacia los diferentes archivos son est\'{a}ticas, as\'{i} como tambi\'{e}n la 
organizacion de los mismos, por tal motivo se puede acceder siempre a un
n\'{u}mero de linea definido y tener la certeza de que la variable buscada se
encuentra all\'{i}.

\subsection{Archivo de Cabecera}
Contiene las declaraciones de funciones.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
#ifndef KSAMP__H 
#define KSAMP__H

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h>
#include <time.h>
#include <unistd.h>

#define MAX_STR 256 
#define DEC_BASE 10


/** ERROR MACROS **/
typedef enum{   OK = 0 , 
                                ERR_CAN_NOT_OPEN_FILE, 
                                ERR_CAN_NOT_CLOSE_FILE,
                                ERR_CAN_NOT_PARSE_UPTIME } status_t ;  

/** AUX FUNCTIONS **/
status_t open_file(const char*,FILE **) ; 
status_t get_uptime(double*,char*) ;
void format_time(double,char*) ;
void remove_newline (char*) ; 


/** PARSE FUNCTIONS **/ 
void parse_colon (char*, char**) ;
status_t parse_uptime( char* ) ;
status_t parse_l(char*,char* ) ; 
status_t parse_cla(int,char*[]) ;

/** PRINT FUNCTIONS **/ 
status_t print_cpuinfo(void) ;  
status_t print_kernel(void) ; 
status_t print_uptime(void) ; 
status_t print_num_fs(void) ;
status_t print_host_and_time(void) ; 
status_t print_disk_requests(void) ;
status_t print_available_and_total_memory() ; 
status_t print_loadavg() ;
status_t print_s() ; 
void print_times(char*) ; 
void look_for(const char*,char*,char**,FILE*) ;
#endif

\end{lstlisting}


\subsection{Funci\'{o}n print\_cpuinfo()}
Imprime tipo y modelo de CPU.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_cpuinfo () {

        status_t st ;
        FILE *  fd ;
        char *  aux ; 
        char *  p ; 
        int     i ;

        aux = (char *) malloc ( sizeof(char)*MAX_STR ) ; 

        if (  (st=open_file("/proc/cpuinfo",&fd)) != OK ) { 
                return st ; 
        } 

        for ( i = 0 ; i < 5 ; i++ ) {
                
                fgets( aux,MAX_STR, fd ) ;
                remove_newline(aux) ; 
                if ( i == 1 ) { 
                        parse_colon(aux,&p) ; 
                        fprintf(stdout,"Type: %s \n",p) ; 
                } 
                if ( i == 4 ) { 
                        parse_colon(aux,&p) ; 
                        fprintf(stdout,"Model: %s \n",p) ; 
                }
        } 
        if (fclose(fd) == EOF) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        } 

        free(aux) ;
        return OK ;
}
\end{lstlisting}

\subsection{Funci\'{o}n print\_kernel()}
Imprime versi\'{o}n de kernel.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_kernel() { 
        status_t st ; 
        FILE * fd ; 
        char * aux ; 

        aux = (char *) malloc ( sizeof(char)*MAX_STR) ;  

        if ( (st=open_file("/proc/sys/kernel/osrelease",&fd)) != OK ) { 
                return st ; 
        } 

        fgets(aux,MAX_STR,fd) ; 
        remove_newline(aux) ; 
        
        fprintf(stdout,"Kernel: %s \n",aux) ; 
        
        if ( fclose(fd) == EOF ) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        } 

        free(aux) ; 

        return OK ; 
}
\end{lstlisting}

\subsection{Funci\'{o}n print\_uptime()}
Imprime el tiempo desde que se inici\'{o} el sistema.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_uptime() { 

        status_t st ; 
        FILE * fd ; 
        char * aux ; 

        aux = (char*) malloc ( sizeof(char)*MAX_STR ) ; 
        
        if ( (st=open_file("/proc/uptime",&fd)) != OK ) { 
                return st ; 
        }

        fgets(aux,MAX_STR,fd) ; 
        parse_uptime(aux) ; 

        fprintf(stdout,"Uptime: %s \n",aux) ; 

        if (fclose(fd) == EOF) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }

        free(aux) ;
        return OK ;     
}
\end{lstlisting}

\subsection{Funci\'{o}n print\_num\_fs()}
Imprime la cantidad de sistemas de archivo soportado por el kernel.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_num_fs() { 
        FILE* fd ; 
        int num_of_fs;
        status_t st ; 

        if ( (st = open_file("/proc/filesystems",&fd)) != OK ) { 
                return st ; 
        }

        num_of_fs = 0;
        while (!feof(fd) && !ferror(fd)) {
                if (getc(fd) == '\n') {
                        ++num_of_fs;
                }
        }
        printf("Number of FS: %d\n", num_of_fs) ; 

        if ( fclose(fd) == EOF ) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }

        return OK ; 
}
\end{lstlisting}

\section{Parte C}
\subsection{Descripci\'{o}n del c\'{o}digo}
La forma de acceder a los datos y como parsearlos es similar a la del apartado B, pero en este caso cabe resaltar
el uso de argumentos al momento de ejecutar el c\'{o}digo, estos argumentos quedan almacenados en \verb=int argc= un entero que contiene la cantidad de argumentos introducidos y \verb=char*argv[]= que basicamente es un arreglo de estos. En este punto puede recibirse el parametro -s.

Otra cosa importante es la forma en que los datos son devueltos por la cantidad de tiempo de cpu utilizados por los usuarios, sistema y procesos idle, los mismos est\'{a}n cuantificados en \verb=USER_HZ= el cual depende de la computadora que est\'{e} corriendo el Kernel o como el mismo este configurado, para poder pasar esta cantidad a segundos hay que usar la funcion que brinda el sistema llamada \verb=sysconf(_SC_CLK_TCK)= la cual nos da la cantidad de Clocks Ticks por segundo, de este modo dividiendo la cantidad \verb=USER_HZ= por la cantidad que retorna la funci\'{o}n, obtenemos el tiempo en segundos.


\subsection{Funci\'{o}n print\_times(char*)}
Imprime la cantidad de tiempo de CPU utilizado para usuarios, sistema y proceso idle.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
void print_times(char* aux){ 
        char* user_str ;
        char* system_str ; 
        char* idle_str ;
        char* tokenp ; 
        char* endp ;
        long user ; 
        long idle ; 
        long system ;

        user_str = (char*) malloc (sizeof(char)*MAX_STR) ; 
        idle_str = (char*) malloc (sizeof(char)*MAX_STR) ; 
        system_str = (char*) malloc (sizeof(char)*MAX_STR) ; 

        tokenp = strtok(aux," ") ; 
        if ( !strcmp(tokenp,"cpu") ){ 
                tokenp = strtok(NULL," ") ; 
                user = strtol(tokenp,&endp,DEC_BASE) ;
        } 

        tokenp = strtok(NULL," ") ; 
        tokenp = strtok(NULL," ") ; 
        system = strtol(tokenp,&endp,DEC_BASE) ; 
        tokenp = strtok(NULL," ") ; 
        idle   = strtol(tokenp,&endp,DEC_BASE) ; 

        user = user/sysconf(_SC_CLK_TCK)  ; 
        system = system/sysconf(_SC_CLK_TCK) ; 
        idle = idle/sysconf(_SC_CLK_TCK) ;

        format_time(user,user_str) ;
        format_time(system,system_str) ; 
        format_time(idle,idle_str) ;

        fprintf(stdout,"UserTime: %s\nSystemTime: %s\nIdleTime: %s\n",user_str,system_str,idle_str) ; 

        free(user_str) ; 
        free(idle_str) ; 
        free(system_str) ;

}
\end{lstlisting}

\subsection{Funci\'{o}n print\_s()}
Imprime:
\begin{itemize}
	\item Cantidad de cambios de contexto. 
	\item Fecha y hora cuando el sistema fue iniciado. 
	\item N\'{u}mero de procesos creados desde el inicio del sistema.
\end{itemize} 
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_s () {   
        FILE* fd ; 
        FILE* uptime_file ; 
        char* aux ; 
        char* endp ; 
        char * tokenp ; 
        double uptime ;
        time_t uptime_since_boot ; 
        time_t now ; 
        time_t boot_time ;
        int uptime_trunk ;
        long ctxt ;
        long processes ;
        status_t st ; 

        if ( (st=open_file("/proc/stat",&fd)) != OK ) { 
                return st ; 
        }
        
        aux = (char*) malloc (sizeof(char)*MAX_STR) ; 

        fgets(aux,MAX_STR,fd) ; 
        
        print_times(aux) ; 

        look_for("ctxt",aux,&tokenp,fd) ;
        ctxt = strtol(tokenp,&endp,DEC_BASE) ; 
        fprintf(stdout,"Context changes: %ld\n",ctxt) ; 

        look_for("processes",aux,&tokenp,fd) ;
        processes = strtol(tokenp,&endp,DEC_BASE) ; 
                
        fprintf(stdout,"Processes: %ld\n",processes) ; 
        if ((st=open_file("/proc/uptime",&uptime_file))!=OK ) {
                return st ; 
        }

        fgets(aux,MAX_STR,uptime_file) ; 
        get_uptime(&uptime,aux) ;
        uptime_trunk = (int) uptime ;   
        uptime_since_boot = (time_t) uptime_trunk ;
        now = time(NULL) ; 
        boot_time = now-uptime_since_boot ; 

        fprintf(stdout,"Boot time: %s",ctime(&boot_time) ) ; 

        if (fclose(fd)== EOF){ 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }

        if (fclose(uptime_file)== EOF){ 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }


        free(aux) ; 
                
        return OK ; 
}
\end{lstlisting}


\section{Parte D}
\subsection{Descripci\'{o}n del c\'{o}digo}
Al igual que el apartado C, aqu\'{i} se reciben parametros al momento de ejecutar el c\'{o}digo, aqu\'{i} es recibido el parametro -l mas otros dos parametros que indican el intervalo de tiempo esperado y el intervalo de tiempo total, en ese orden.

\subsection{Funci\'{o}n print\_disk\_requests()}
Imprime el n\'{u}mero de peticiones a disco realizadas
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_disk_requests() { 
        FILE * fd ; 
        char * aux ; 
        char * tokenp ; 
        char * endp ;
        int flag, i; 
        long reads ;
        long writes ;
        status_t st ;
        
        aux = (char*) malloc ( sizeof(char)*MAX_STR ) ; 
        if ( (st=open_file("/proc/diskstats",&fd)) != OK ) { 
                return st ; 
        }

        flag = 1 ; 

        while ( flag ) {  
                fgets(aux,MAX_STR,fd) ; 
                for (tokenp = strtok(aux," "); tokenp != NULL; tokenp = strtok(NULL, " "))
                {
                        if(!strcmp(tokenp,"sda")) { 
                                flag = 0 ; 
                                break ;
                        } 
                }
        }

        tokenp = strtok(NULL," \t") ; 
        reads = strtol(tokenp,&endp,DEC_BASE) ;  
        for ( i = 0 ; i < 4 ; i++ ) {
                tokenp=strtok(NULL,"\t ") ; 
        }

        writes = strtol(tokenp,&endp,DEC_BASE) ; 

        fprintf(stdout,"Disks request: %ld\n",reads+writes) ; 

        if ( fclose(fd) == EOF ) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }

        free (aux) ;
        
        return OK ; 
}
\end{lstlisting}

\subsection{Funci\'{o}n print\_avaliable\_and\_total\_memory()}
Imprime:
\begin{itemize}
	\item Cantidad de memoria configurada en el hardware.
	\item Cantidad de memoria disponible.
\end{itemize}
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_available_and_total_memory() {
        FILE * fd ; 
        char * aux ; 
        char * endp ; 
        char * p ; 
        long total ; 
        long available ;
        status_t st ; 

        if ((st=open_file("/proc/meminfo",&fd))!=OK ){ 
                return st ; 
        }

        aux = (char*) malloc ( sizeof(char)*MAX_STR ) ; 

        fgets(aux,MAX_STR,fd) ; 
        parse_colon(aux,&p) ; 
        total = strtol(p,&endp,DEC_BASE) ; 

        fgets(aux,MAX_STR,fd) ; 
        parse_colon(aux,&p) ; 
        available = strtol(p,&endp,DEC_BASE) ; 

        fprintf(stdout,"Memory Available/Total: %ld/%ld\n",total,available ) ; 

        if ( fclose(fd) == EOF ) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }

        free (aux) ;

        return OK ;     
} 
\end{lstlisting}

\subsection{Funci\'{o}n print\_loadavg()}
Imprime la lista de los promedios de carga de 1 minuto.
\lstset{language=C, breaklines=true, basicstyle=\footnotesize}
\begin{lstlisting}[frame=single]
status_t print_loadavg() {
        FILE * fd ; 
        char* aux ;  
        char* endp ; 
        double loadavg ; 
        status_t st ; 

        if ((st=open_file("/proc/loadavg",&fd)) != OK ) { 
                return st ; 
        }

        aux = (char*) malloc (sizeof(char)*MAX_STR) ; 
laboratorio
        fgets(aux,MAX_STR,fd) ; 
        loadavg = strtod(aux,&endp) ; 
        
        fprintf(stdout,"Load average: %.2f\n",loadavg) ; 

        if ( fclose(fd) == EOF ) { 
                return ERR_CAN_NOT_CLOSE_FILE ; 
        }
        free(aux) ; 

        return OK ; 
} 
\end{lstlisting}

\chapter{Conclusi\'{o}n}\label{cap.conclusion}
Fu\'{e} muy interesante entender como el kernel maneja la informaci\'{o}n de los distintos tipos de hardware, perifericos, informaci\'{o}n del usuario, etc. y que estos est\'{a}n escritos en simples archivos virtuales de texto plano que pueden ser accedidos incluso ser modificados por el usuario debido a la particularidad que tiene Linux de ser de c\'{o}digo abierto; cada variable de sistema se encuentra en alg\'{u}n archivo de estos y son modificados por el sistema en cualquier momento.

\begin{thebibliography}{99}
\bibitem{C} The ANSI C Programing Lenguage. Brian W. Kernighan, Dennis M. Ritchie. Prentice Hall 1988
\bibitem{Linux} Linux Cross Reference Web-Site: \url{http://lxr.free-electrons.com}
\bibitem{Web} Web de Linux Web-Site: \url{http://www.linuxtotal.com.mx/index.php}
\end{thebibliography}
\end{document}